#ifndef _CU_INT3_H_
#define _CU_INT3_H_

//**********************************************************************************
// int3 operators and functions
//**********************************************************************************

SDH_CALL int3 operator + (const int3 & u, int v) { int3 r = { u.x + v, u.y + v, u.z + v }; return r; }
SDH_CALL int3 operator - (const int3 & u, int v) { int3 r = { u.x - v, u.y - v, u.z - v }; return r; }
SDH_CALL int3 operator * (const int3 & u, int v) { int3 r = { u.x * v, u.y * v, u.z * v }; return r; }
SDH_CALL int3 operator / (const int3 & u, int v) { int3 r = { u.x / v, u.y / v, u.z / v }; return r; }
SDH_CALL int3 operator % (const int3 & u, int v) { int3 r = { u.x % v, u.y % v, u.z % v }; return r; }

SDH_CALL int3 operator + (int v, const int3 & u) { int3 r = { v + u.x, v + u.y, v + u.z }; return r; }
SDH_CALL int3 operator - (int v, const int3 & u) { int3 r = { v - u.x, v - u.y, v - u.z }; return r; }
SDH_CALL int3 operator * (int v, const int3 & u) { int3 r = { v * u.x, v * u.y, v * u.z }; return r; }
SDH_CALL int3 operator / (int v, const int3 & u) { int3 r = { v / u.x, v / u.y, v / u.z }; return r; }
SDH_CALL int3 operator % (int v, const int3 & u) { int3 r = { v % u.x, v % u.y, v % u.z }; return r; }

SDH_CALL int3 operator + (const int3 & u, const int3 & v) { int3 r = { u.x + v.x, u.y + v.y, u.z + v.z }; return r; }
SDH_CALL int3 operator - (const int3 & u, const int3 & v) { int3 r = { u.x - v.x, u.y - v.y, u.z - v.z }; return r; }
SDH_CALL int3 operator * (const int3 & u, const int3 & v) { int3 r = { u.x * v.x, u.y * v.y, u.z * v.z }; return r; }
SDH_CALL int3 operator / (const int3 & u, const int3 & v) { int3 r = { u.x / v.x, u.y / v.y, u.z / v.z }; return r; }
SDH_CALL int3 operator % (const int3 & u, const int3 & v) { int3 r = { u.x % v.x, u.y % v.y, u.z % v.z }; return r; }

SDH_CALL int3 operator - (const int3 & u) { int3 r = { -u.x, -u.y, -u.z }; return r; }

SDH_CALL int3 & operator += (int3 & u, const int3 & v) { u.x += v.x; u.y += v.y; u.z += v.z; return u; }
SDH_CALL int3 & operator -= (int3 & u, const int3 & v) { u.x -= v.x; u.y -= v.y; u.z -= v.z; return u; }
SDH_CALL int3 & operator *= (int3 & u, const int3 & v) { u.x *= v.x; u.y *= v.y; u.z *= v.z; return u; }
SDH_CALL int3 & operator /= (int3 & u, const int3 & v) { u.x /= v.x; u.y /= v.y; u.z /= v.z; return u; }
SDH_CALL int3 & operator %= (int3 & u, const int3 & v) { u.x %= v.x; u.y %= v.y; u.z %= v.z; return u; }

SDH_CALL int3 & operator += (int3 & u, int v) { u.x += v; u.y += v; u.z += v; return u; }
SDH_CALL int3 & operator -= (int3 & u, int v) { u.x -= v; u.y -= v; u.z -= v; return u; }
SDH_CALL int3 & operator *= (int3 & u, int v) { u.x *= v; u.y *= v; u.z *= v; return u; }
SDH_CALL int3 & operator /= (int3 & u, int v) { u.x /= v; u.y /= v; u.z /= v; return u; }
SDH_CALL int3 & operator %= (int3 & u, int v) { u.x %= v; u.y %= v; u.z %= v; return u; }

SDH_CALL int3 catmullrom (const int3 & P0, const int3 & P1, const int3 & P2, const int3 & P3, float t)
{
  const float ts = t * t;
  const float tc = t * ts;

  return (P0 * (-tc + 2.0f * ts - t) + P1 * (3.0f * tc - 5.0f * ts + 2.0f) + P2 * (-3.0f * tc + 4.0f * ts + t) + P3 * ( tc - ts)) * 0.5f;
}
SDH_CALL int3 lerp      (const int3 & u, const int3 & v, float t ) { return u + t * (v - u); }
SDH_CALL int  dot       (const int3 & u, const int3 & v) { return (u.x*v.x + u.y*v.y + u.z*v.z); }
SDH_CALL int3 cross     (const int3 & u, const int3 & v) { int3 r = { u.y*v.z-u.z*v.y, u.z*v.x-u.x*v.z, u.x*v.y-u.y*v.x} ; return r; }
SDH_CALL int3 clamp     (const int3 & u, int a, int b) { int3 r = { clamp(u.x, a, b), clamp(u.y, a, b), clamp(u.z, a, b) }; return r; }

SDH_CALL float  triple    (const int3 & a, const int3 & b, const int3 & c ) { return dot(a, cross(b, c) ); }
SDH_CALL float  length    (const int3 & u) { return sqrtf(sqr(u.x) + sqr(u.y) + sqr(u.z)); }
SDH_CALL int3   normalize (const int3 & u) { return u / length(u); }

SDH_CALL int2 xy        (const int3 & v) { int2 u = { v.x, v.y }; return u; }

SDH_CALL int3 min(const int3 & u, const int3 & v){ int3 r = {min(u.x, v.x), min(u.y, v.y), min(u.z, v.z)}; return r; }
SDH_CALL int3 max(const int3 & u, const int3 & v){ int3 r = {max(u.x, v.x), max(u.y, v.y), max(u.z, v.z)}; return r; }

SDH_CALL int  sad(const int3 & u, const int3 & v) { return (abs(u.x - v.x) + abs(u.y - v.y) + abs(u.z - v.z)); } // Sum of Absolute Differences for xyz components 
SDH_CALL int  ssd(const int3 & u, const int3 & v) { return (sqr(u.x - v.x) + sqr(u.y - v.y) + sqr(u.z - v.z)); } // Sum of Squared  Differences for xyz components 

SDH_CALL int3 set(int3 & v, int x = 0, int y = 0, int z = 0) 
{ 
  v.x = x; v.y = y; v.z = z; return v; 
}
SDH_CALL int3 set(int3 & v, int2 xy, int z = 0) 
{ 
  v.x = xy.x; v.y = xy.y; v.z = z; return v; 
}
SDH_CALL int3 i3(int x) { int3 r = {x, x, x}; return r;}
SDH_CALL int3 i3(int x, int y, int z) { int3 r = {x, y, z}; return r;}
SDH_CALL int3 i3(const int2 & u, int z) { int3 r = {u.x, u.y, z}; return r; }


#endif